#ifndef _HALL_H_
#define _HALL_H_

#include "Define.h"
#include "LogEx.h"
#include "StackTrace.h"
#include "Header.h"
#include "Timer.h"
#include "RoomManager.h"
#include "RoomBase.h"
#include "TeamManager.h"
#include "ActivityConfig.h"
#include <map>
#include <list>
#include <string>
#include <vector>
#include "msg_common.h"
#include "HallConfig.h"
#include "GameLogManager.h"
#include "UDPClient.h"

class CRoomBase;
class CPlayerBase;
class IGameService;
class CActivityManager;
class CHall
{
    SINGLETON_CLASS_DEFINE(CHall);

public:
	template<typename TRoom, typename TPlayer>
	bool Init(s32 gameid, u64 sid, const char *cfgfile="game.xml", const char *activityfile="activity.xml")
	{
        if( !CHallConfig::Instance().Load(sid, cfgfile) )
        {
			LOG_ERROR( "CHall::Init load[%s] failed.", cfgfile );
            return false;
        }
        m_cfgfile = cfgfile;
        m_gamelogMgr = new CGameLogManager();
        if( !m_gamelogMgr->Start() )
        {
			LOG_ERROR( "CHall::Init GameLogManager Start failed." );
            return false;
        }

        m_roomTimerId = -1;
        m_logTimerId = -1;
        m_resTimerId = -1;
		m_gameTimesTimerId = -1;
        m_gameid = CHallConfig::Instance().GetCfg().gameId;
        m_dbServerId = CHallConfig::Instance().GetCfg().dbSid;
        m_centerServerId = CHallConfig::Instance().GetCfg().centerSid;
        m_baseAnte = CHallConfig::Instance().GetCfg().ante;
        if( !CRoomManager::Instance().Init(
            CHallConfig::Instance().GetCfg().roomCount) )
        {
			LOG_ERROR( "CHall::Init room manager init failed" );
            return false;
        }
        CTeamManager::Instance().Init( gameid, 
            CHallConfig::Instance().GetCfg().teamQueueCount,
            CHallConfig::Instance().GetCfg().minPlayerCount,
            CHallConfig::Instance().GetCfg().maxPlayerCount,
            CHallConfig::Instance().GetCfg().teamMatchMode );

		m_roomCount = CHallConfig::Instance().GetCfg().roomCount;
		m_minRoomPlayerCount = CHallConfig::Instance().GetCfg().minPlayerCount;
		m_maxRoomPlayerCount = CHallConfig::Instance().GetCfg().maxPlayerCount;
		m_maxRoomBeholderCount = CHallConfig::Instance().GetCfg().maxBeholderCount;
		m_maxPlayerCount = m_maxRoomPlayerCount * m_roomCount;
		if( m_maxPlayerCount <= 0 )
		{
			LOG_ERROR( "CHall::Init m_maxPlayerCount[%d] wrong", m_maxPlayerCount );
			return false;
		}

		m_playerTemplate = new TPlayer();
		if( !m_playerTemplate )
		{
			LOG_ERROR( "CHall::Init new player template failed" );
			return false;
		}

		m_rooms = new CRoomBase*[ m_roomCount ];
		if( !m_rooms )
		{
			LOG_ERROR( "CHall::Init new room ptr array failed" );
			return false;
		}
		for( s32 i=0; i<m_roomCount; ++i )
		{
			m_rooms[i] = new TRoom( i );
			if( !m_rooms[i] )
			{
				LOG_ERROR( "CHall::Init new room[%d] failed", i );
				return false;
			}
            m_rooms[i]->SetAnte( m_baseAnte );
		}
        srand(time(NULL));
        _Init();
        
        m_activityFile = activityfile; 
        CActivityConfigManager::Instance().Load( activityfile );

        StartTimer();
        NotifyRoomCenterServerStart();
		return true;
	}

	void Fini();

	s32 RoomCount();
	s32 MinRoomPlayerCount();
	s32 MaxRoomPlayerCount();
	s32 MaxRoomBeholderCount();
	s32 MaxPlayerCount();
	s32 CurPlayerCount();

	CRoomBase* FindRoom(s32 roomid);
	CPlayerBase* FindPlayer(u64 gateid, u64 clientid);
	CPlayerBase* FindPlayer(u64 userid);
    void Close(u64 gateid, u64 clientid);
    void SendMsg(u64 gateid, u64 clientid, s32 msgid, const IMessage &msg);
	void BroadcastMsg(s32 msgid, const IMessage &msg);
	s32 AddTimer(u32 elapse, SGLib::CallBackFunc func, void *data, s32 len, bool isPersist);
    void DelTimer(s32 timerid);
    s32 GameId(){ return m_gameid; }
    void KickOut(CPlayerBase &player, s32 reason);
    CActivityManager* ActivityManager() { return m_activityMgr; };

	CPlayerBase* PlayerEnterHall(u64 gateid, u64 clientid, u64 userid);
	void PlayerLeaveHall(CPlayerBase &player, s32 reason);
	void PlayerEnterRoom(CPlayerBase &player, CRoomBase &room, int seatno, const std::string &passwd);
	void PlayerLeaveRoom(CPlayerBase &player, s32 reason);
	void PlayerSitDown(CPlayerBase &player, int seatno);
	void PlayerStandUp(CPlayerBase &player);
	void PlayerReady(CPlayerBase &player);
	void PlayerCancelReady(CPlayerBase &player);
    void PlayerTrusteeShip(CPlayerBase &player);
    void PlayerCancelTrusteeShip(CPlayerBase &player);
    void PlayerRoomChat(CPlayerBase &player, s8 chattype, const std::string &chatcontent, s8 anonymous, std::vector<u64> &receiver, s8 isend, std::vector<std::string> &param);
    void PlayerCreateRoom(CPlayerBase &player, const std::string &name, const std::string &passwd, s32 ante, const std::string &data);
    void PlayerMatchRequest(CPlayerBase &player);
    void PlayerSetRoomAnte(CPlayerBase &player, s32 ante);
    void PlayerGetCenterMoneyDone(CPlayerBase &player, std::vector<s64> &money, commonproto::OnlineData &onlineinfo);
    void PlayerGetRoomList(CPlayerBase &player);
    void PlayerGetActivityAward(CPlayerBase &player, s32 activityid);
    void PlayerDismissFriendRoom(CPlayerBase &player);
    void PlayerLeaveFriendRoom(CPlayerBase &player);
    void PlayerAgreeDismissFriendRoom(CPlayerBase &player, s32 agree);
    void PlayerStartGameFriendRoom(CPlayerBase &player);
    void KickOutRoom(CPlayerBase &player, u64 kickuserid);
    void UseInteractItem(CPlayerBase &player, s32 to, s32 item);
    void UserCuiPai(CPlayerBase &player, commonproto::UserCuiPaiCommon &cuipai);
    void GetUserInfo(CPlayerBase &player, u64 userid);

	void StartTimer();

	bool SendMsg2Server(u64 serverid, u32 msgid, const IMessage &msg);
	bool SendMsg2Server(u64 serverid, const byte *data, s32 len);
	bool SendMsg2DBProxy(u64 dbserverid, u32 msgid, IMessage &msg, s32 dbid, u64 syncid);
	bool SendMsg2DBProxy(u32 msgid, IMessage &msg, u64 syncid);
	bool SendLogMsg2DBProxy(u32 msgid, IMessage &msg, u64 syncid);

    bool NotifyDBProxyExecSQL(u64 dbserverid, const std::string &sql, s32 dbid, u64 syncid);
    bool NotifyDBProxyExecSQL(const std::string &sql, u64 syncid);
    bool NotifyDBProxyExecSQL(const char *sql, u64 syncid);

	void UpdateGameTimes2DBProxy(CRoomBase *proom, CPlayerBase *pplayer, s32 nd);
    void SendMsg2Center(u32 msgid, IMessage &msg);

	// proto process
public:
	void OnMsgUserAuthenReq(u64 gateid, u64 clientid, const byte *msg, s32 len);
	void OnMsgUserClose(u64 gateid, u64 clientid);
	void OnMsgUserEnterRoomReq(u64 gateid, u64 clientid, const byte *msg, s32 len);
	void OnMsgUserLeaveRoomReq(u64 gateid, u64 clientid, const byte *msg, s32 len);
	void OnMsgUserSitDownReq(u64 gateid, u64 clientid, const byte *msg, s32 len);
	void OnMsgUserStandUpReq(u64 gateid, u64 clientid, const byte *msg, s32 len);
	void OnMsgUserReady(u64 gateid, u64 clientid, const byte *msg, s32 len);
	void OnMsgUserCancelReady(u64 gateid, u64 clientid, const byte *msg, s32 len);
    void OnMsgUserTrusteeShip(u64 gateid, u64 clientid, const byte *msg, s32 len);
    void OnMsgUserCancelTrusteeShip(u64 gateid, u64 clientid, const byte *msg, s32 len);
    void OnMsgUserRoomChat(u64 gateid, u64 clientid, const byte *msg, s32 len);
    void OnMsgUserCreateRoom(u64 gateid, u64 clientid, const byte *msg, s32 len);
    void OnMsgMatchPlayer(u64 gateid, u64 clientid, const byte *msg, s32 len);
    void OnMsgSetRoomAnte(u64 gateid, u64 clientid, const byte *msg, s32 len);
    void OnMsgGetRoomList(u64 gateid, u64 clientid, const byte *msg, s32 len);
    void OnMsgGetActivityAward(u64 gateid, u64 clientid, const byte *msg, s32 len);
    void OnMsgFriendRoomDismiss(u64 gateid, u64 clientid, const byte *msg, s32 len);
    void OnMsgFriendRoomLeave(u64 gateid, u64 clientid, const byte *msg, s32 len);
    void OnMsgFriendRoomAgreeDismiss(u64 gateid, u64 clientid, const byte *msg, s32 len);
    void OnMsgFriendRoomStartGame(u64 gateid, u64 clientid, const byte *msg, s32 len);
    void OnMsgSelfLocationInfo(u64 gateid, u64 clientid, u32 remoteip, const byte *msg, s32 len);
    void OnMsgKickOutRoom(u64 gateid, u64 clientid, const byte *msg, s32 len);
    void OnMsgUseInteractItem(u64 gateid, u64 clientid, const byte *msg, s32 len);
    void OnMsgUserCuiPai(u64 gateid, u64 clientid, const byte *msg, s32 len);
    void OnMsgGetUserInfo(u64 gateid, u64 clientid, const byte *msg, s32 len);

public:
    void OnMsgDBProxyUserLogin(const byte *msg, s32 len);
    void OnMsgCenterUserGetMoney(const byte *msg, s32 len);
    void OnMsgCenterUserUpdateMoney(const byte *msg, s32 len);
    void OnMsgDBProxyUserActivityData(const byte *msg, s32 len);
    void OnMsgDBProxyLoadUserItems(const byte *msg, s32 len);
    void OnMsgDBProxyCardTypeAward(const byte* msg,s32 len);
    void OnMsgRoomCenterCreatRoom(const byte *msg, s32 len);
    void OnMsgCenterUserRecharge(const byte *msg, s32 len);

public:
	void DumpAllPlayers(std::vector<u64> &vec);
    void GetUserMoneyInfo(CPlayerBase &player, bool onlineSet=true);
    void UpdateUserMoney(u64 userid, std::vector<s64> &upmoney, s32 reason);
    void DissolveRoomReMatch(CRoomBase &room); // 解散房间将房间中人重新匹配
    void AddGameLog(u64 userid, s32 gameid, u64 serverid, s32 roomid, u64 battleid, s64 winmoney, s32 tax, s8 isoffline, s8 isrobot, u64 tbegin, u64 tend, std::string &channel, s32 reserve1=0, s32 reserve2=0, const char *reserve3="");
    void BroadcastUserEnterHall(CPlayerBase &player);
    void BroadcastUserLeaveHall(CPlayerBase &player);
    void BroadcastUserEnterRoom(CPlayerBase &player, s32 roomid, s32 seatno);
    void BroadcastUserLeaveRoom(CPlayerBase &player, s32 roomid, s32 seatno);
    bool InitActivityData(CPlayerBase &player, const ActivityItem &activity, void *activityData);
    bool GameEndUpdateActivity(CPlayerBase &player, const ActivityItem &activity, void *activityData);
    int CheckActivityState(const ActivityItem &activity, void *activityData);
    void GetActivityAwardDone(const ActivityItem &activity, void *activityData);
    void ReloadResource();
    bool IsFriendMode();
    u64 GenBattleId(s32 rid);
    // room center
    void NotifyRoomCenterServerStart();
    void NotifyRoomCenterServerStop();
    void NotifyRoomCenterGameStart(CRoomBase &room, std::vector<u64> &uids, bool deccard);
    void NotifyRoomCenterGameStop(CRoomBase &room, s32 reason);
    void NotifyRoomCenterUserInOut(s32 roomid, u64 uid, s32 inout, u64 uuid, std::string &nickname);
    void NotifyRoomCenterRoomStatus();
    void NotifyRoomCenterDecCard(CRoomBase &room);

    void LogFriendGameData(CPlayerBase &player, s64 score);
    void LogFriendGameRoundData(CPlayerBase &player, s32 endstate);

    void LogGameRecord(s32 gameid, u64 battleid, s32 round, const std::string &data, s32 isend);
    void LogActivityAward(u64 userid, s32 activityid, s32 param1=0, s32 param2=0, s32 param3=0, s32 param4=0, s32 param5=0, s32 param6=0, s32 param7=0, s32 param8=0);

    void BroadcastGameNotice(const char *channel, const char *notice, const char *producer);
    static void ReLoadGameConfig(void *data, s32 len);
    void NotifyBalanceGameData();

private:
    void _Init();
    void _AddPlayer(u64 gateid, u64 clientid, u64 userid, CPlayerBase &player);
	bool _RemovePlayer(u64 gateid, u64 clientid, u64 userid);
	CPlayerBase *_GetFreePlayer();
	void _PutPlayer(CPlayerBase *player);
	static void _CheckRoomTimeOutTimer(void *data, s32 len);
    static void _CheckGameLogTimer(void *data, s32 len);
    static void _LoadResTimer(void *data, s32 len);
	static void _UpdateGameTimesTimer(void *data, s32 len);
    void _BreakUserComeBack(CPlayerBase &old, u64 userid, u64 gateid, u64 clientid, std::string &token);
    void _NotifyCenterUserOnline(u64 userid);
    void _NotifyCenterUserOffline(u64 userid);
    void _LoadUserActivityData(CPlayerBase &player);
    void _LoadUserItems(CPlayerBase &player);
    void _DoBreakUserComeBack(CPlayerBase &player, std::string &token);
    void _ReportOnlineCount();

private:
    s32 m_gameid;
    u64 m_dbServerId;
    u64 m_centerServerId;
	s32 m_roomCount;			// 大厅房间个数
	s32 m_minRoomPlayerCount;	// 最小的开始游戏人数
	s32 m_maxRoomPlayerCount;	// 房间人数上限(座位数)
	s32 m_maxRoomBeholderCount; // 房间旁观人数上限
	s32 m_maxPlayerCount;		// 大厅人数上限
    s32 m_baseAnte;             // 基础底注

	CRoomBase **m_rooms;		// 游戏房间数组, 房间ID直接对应数组下标
	std::map<u64, std::map<u64, CPlayerBase*> > m_playersPosMap;	// 玩家索引1 <gateid, clientid>
	std::map<u64, CPlayerBase*> m_playersIpMap;						// 玩家索引2 <userid>

	CPlayerBase *m_playerTemplate;		// 玩家对象模板,玩家对象依此创建
	std::list<CPlayerBase*> m_freeList;	// 空闲玩家队列

    CGameLogManager *m_gamelogMgr;

    std::string m_activityFile;
    s32 m_roomTimerId;
    s32 m_logTimerId;
    s32 m_resTimerId;
	s32 m_gameTimesTimerId;
    CActivityManager *m_activityMgr;

    // udp消息服
    class CMyUDPClient : public CUDPClient
    {
    public:
        virtual void OnRecv(const char *buf, int len) {}
        std::string m_passwd;
    } m_udpclient;

    // 
    std::string m_cfgfile;
};

#endif
